TypeScript 50.6%
JavaScript 46.1%
SQL 2.1%
Shell 0.6%
CSS 0.5%
1import { NextRequest, NextResponse } from "next/server";2import { and, eq } from "drizzle-orm";3import { db } from "@/db/client";4import { listingMedia } from "@/db/schema";5import { assertSameOrigin, requireUser } from "@/lib/auth/session";6import { getListingFull, assertOwner } from "@/lib/listings/service";7import { removeFiles } from "@/lib/listings/media";8import { apiError, handle } from "@/lib/api";9import { audit } from "@/lib/auth/audit";10export const dynamic = "force-dynamic";11export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string; mediaId: string }> }) {12 try {13 await assertSameOrigin(); const u = await requireUser(); const { id, mediaId } = await params;14 const l = await getListingFull(id); if (!l) return apiError(404, "not_found", "Annonce introuvable"); assertOwner(l, u.id, u.roles);15 const [m] = await db().select().from(listingMedia).where(and(eq(listingMedia.id, mediaId), eq(listingMedia.listingId, id))).limit(1); if (!m) return apiError(404, "not_found", "Média introuvable");16 await db().update(listingMedia).set({ status: "DELETED" }).where(eq(listingMedia.id, mediaId)); if (!m.storageKey.startsWith("pending/")) removeFiles(m.storageKey);17 await audit("media.delete", { actorId: u.id, objectType: "listing_media", objectId: mediaId });18 return NextResponse.json({ ok: true });19 } catch (e) { return handle(e); }20}21